package org.mapdroid.maps.gmaps.overlay;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import org.mapdroid.data.adt.Client;
import org.mapdroid.data.adt.MdService;
import org.mapdroid.login.LoginActivity;
import org.mapdroid.maps.gmaps.MdMapActivity;
import org.mapdroid.maps.gmaps.MdMapView;
import org.mapdroid.maps.gmaps.overlay.info.AddressInfoActivity;
import org.mapdroid.maps.gmaps.overlay.info.ParkingInfoActivity;
import org.mapdroid.maps.gmaps.overlay.info.ServiceInfoActivity;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.os.Parcelable;
import android.os.Vibrator;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.GestureDetector.OnDoubleTapListener;
import android.view.GestureDetector.OnGestureListener;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapView;
import com.google.android.maps.OverlayItem;

public class MdMarkerItemizedOverlay extends ItemizedOverlay<OverlayItem> implements OnGestureListener, OnDoubleTapListener{
	private MdMapView mapView;
	private Context context;
	private List<OverlayItem> markers;
	private List<Parcelable> markersExtra;
	private ArrayList<MdService> serviceList;
	private Client client;
	private GestureDetector gestureDetector;
	private Drawable markerDrawable;
	private int itemTappedIndex;
	private int overlayId;
	private Vibrator vibrator;
	
	public static final String SERVICE_DATA = "SERVICE_DATA";
	public static final String OVERLAY_DATA = "OVERLAY_DATA";

	public static final String STRING_DATA	= "STRING_DATA";
	public static final String OBJECT		= "OBJECT";
	public static final String LIST 		= "LIST";
	public static final String RANGE		= "RANGE";
	public static final String POSITION 	= "POSITION";
	
	public MdMarkerItemizedOverlay(MdMapView map, Context con) {
		super(null);
		// TODO Auto-generated constructor stub
		this.mapView	= map;
		this.context 	= con;
		this.markers 	= new LinkedList<OverlayItem>();
		markersExtra = new LinkedList<Parcelable>();
		//this.markerDrawable	= defaultMarker;
		this.gestureDetector = new GestureDetector(this.context, this);
		this.itemTappedIndex = -1;
		//this.overlayId = overlayId;
		this.vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
		
		this.serviceList = null;
		this.client = null;
	}
	
	public MdMarkerItemizedOverlay(MdMapView map, Context con, Drawable defaultMarker, int overlayId) {
		super(boundCenterBottom(defaultMarker));
		// TODO Auto-generated constructor stub
		this.mapView	= map;
		this.context 	= con;
		this.markers 	= new LinkedList<OverlayItem>();
		markersExtra = new LinkedList<Parcelable>();
		this.markerDrawable	= defaultMarker;
		this.gestureDetector = new GestureDetector(this.context, this);
		this.itemTappedIndex = -1;
		this.overlayId = overlayId;
		this.vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
		
		this.serviceList = null;
		this.client = null;
	}
	
	public MdMarkerItemizedOverlay(MdMapView map, Context con, Drawable defaultMarker, int overlayId, ArrayList<MdService> list) {
		super(boundCenterBottom(defaultMarker));
		// TODO Auto-generated constructor stub
		this.mapView	= map;
		this.context 	= con;
		this.markers 	= new LinkedList<OverlayItem>();
		markersExtra = new LinkedList<Parcelable>();
		this.markerDrawable	= defaultMarker;
		this.gestureDetector = new GestureDetector(this.context, this);
		this.itemTappedIndex = -1;
		this.overlayId = overlayId;
		this.vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
		
		this.serviceList = list;
	}
	
	public void addItem(OverlayItem item, Parcelable p){
		markers.add(item);
		markersExtra.add(p);
		populate();
	}
	
	public void addItem(GeoPoint position, String label, String snippet, Parcelable p){
		OverlayItem item = new OverlayItem(position, label, snippet);
		markers.add(item);
		markersExtra.add(p);
		populate();
	}
	
	public void addItem(Drawable newMarker, GeoPoint position, String label, String snippet, Parcelable p){
		OverlayItem item = new OverlayItem(position, label, snippet);
		if(newMarker==null)
			item.setMarker(null);
		else
			item.setMarker(boundCenterBottom(newMarker));
		
		markers.add(item);
		markersExtra.add(p);
		populate();
	}
	
	public void addItem(List<OverlayItem> list, List<Parcelable> p){
		markers.addAll(list);
		markersExtra.addAll(p);
		populate();
	}
	
	public void removeItem(int index) throws UnsupportedOperationException, IndexOutOfBoundsException{
		try{
			markers.remove(index);
			markersExtra.remove(index);
			populate();
		} catch(IndexOutOfBoundsException e1){
			throw e1;
		} catch(UnsupportedOperationException e2){
			throw e2;
		}
		
	}
	
	public void removeAllItems() throws UnsupportedOperationException{
		try{
			markers.clear();
			markersExtra.clear();
			populate();
		} catch(UnsupportedOperationException e){
			throw e;
		}
	}
	
	public void setItem(int index, GeoPoint position, String label, String snippet, Parcelable p){
		OverlayItem item = new OverlayItem(position, label, snippet);
		try{
			if(size()>0){
				markers.set(index, item);
				markersExtra.set(index, p);
			}
			else{
				markers.add(item);
				markersExtra.add(p);
			}
			populate();
		}
		catch(UnsupportedOperationException e){
			e.printStackTrace();
		}
		catch(ClassCastException e){
			e.printStackTrace();
		}
		catch(IllegalArgumentException e){
			e.printStackTrace();
		}
		catch(IndexOutOfBoundsException e){
			e.printStackTrace();
		}
	}
	
	public void setItem(int index, Drawable newMarker, GeoPoint position, String label, String snippet, Parcelable p){
		OverlayItem item = new OverlayItem(position, label, snippet);
		item.setMarker(boundCenterBottom(newMarker));
		try{
			if(size()>0){
				markers.set(index, item);
				markersExtra.set(index, p);
			}
			else{
				markers.add(item);
				markersExtra.add(p);
			}
			populate();
		}
		catch(UnsupportedOperationException e){
			e.printStackTrace();
		}
		catch(ClassCastException e){
			e.printStackTrace();
		}
		catch(IllegalArgumentException e){
			e.printStackTrace();
		}
		catch(IndexOutOfBoundsException e){
			e.printStackTrace();
		}
	}
	
	@Override
	protected OverlayItem createItem(int i) {
		// TODO Auto-generated method stub
		return markers.get(i);
	}

	public Parcelable getExtra(int i){
		return markersExtra.get(i);
	}
	
	@Override
	public int size() {
		// TODO Auto-generated method stub
		return markers.size();
	}
	
	@Override
	protected boolean hitTest(OverlayItem item, Drawable marker, int x, int y){
		super.hitTest(item, marker, x, y);
		Point p = new Point();
		mapView.getProjection().toPixels(item.getPoint(), p);
		if( x > p.x - marker.getIntrinsicWidth()/2 && 
				x < p.x + marker.getIntrinsicWidth()/2 && 
				y > p.y - marker.getIntrinsicHeight() && 
				y < p.y)
			return true;
		return false;
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event, MapView map){
		int size = size();
		if(size==0)
			return false;
		
		super.onTouchEvent(event, map);
		int x = (int) event.getX();
		int y = (int) event.getY();
		
		for(int i=0; i<size; i++){
			if(hitTest(markers.get(i), markerDrawable, x, y)){
				itemTappedIndex=i;
				i=size;
				gestureDetector.onTouchEvent(event);
				mapView.hasEventHandled(true);
				return true;
			}
		}
		return false;
	}
	
	@Override
	public boolean onDown(MotionEvent e) {
		// TODO Auto-generated method stub
		vibrator.vibrate(75);
		return false;
	}

	@Override
	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
			float velocityY) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void onLongPress(MotionEvent e) {
		// TODO Auto-generated method stub
		mapView.setLastMarkerTapped(itemTappedIndex, overlayId);
		mapView.showContextMenu();
	}

	@Override
	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
			float distanceY) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public void onShowPress(MotionEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public boolean onSingleTapUp(MotionEvent e) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean onDoubleTap(MotionEvent arg0) {
		// TODO Auto-generated method stub
		Intent intent = new Intent();
		intent.putExtra(MdMarkerItemizedOverlay.OBJECT, markersExtra.get(itemTappedIndex));
		intent.putExtra(MdMarkerItemizedOverlay.OVERLAY_DATA, overlayId);
		vibrator.vibrate(new long[]{0, 50, 50, 50}, -1);
		
		switch(this.overlayId){
			case MdMapView.RESTAURANT_OVERLAY_INDEX:
			case MdMapView.CLOTHING_OVERLAY_INDEX:
			case MdMapView.BEAUTY_CENTER_OVERLAY_INDEX:
			case MdMapView.GYM_OVERLAY_INDEX:
			case MdMapView.SEARCH_SERVICE_OVERLAY_INDEX:
				intent.setClass(context, ServiceInfoActivity.class);
				//intent = new Intent(context, ParkingInfoActivity.class);
				//intent.putExtra(MdMarkerItemizedOverlay.OBJECT, (Parking)markersExtra.get(itemTappedIndex));
				intent.putExtra(LoginActivity.CLIENT_OBJECT, client);
				//intent.putExtra(MdMarkerItemizedOverlay.OVERLAY_DATA, MdMapView.PARKING_OVERLAY_INDEX);
				//((Activity) context).startActivityForResult(intent, MdMapActivity.DIRECTIONS_INTENT_ID);
				((Activity) context).startActivityForResult(intent, MdMapActivity.SERVICE_INTENT_ID);
				return true;
					
			case MdMapView.PARKING_OVERLAY_INDEX:
				intent.setClass(context, ParkingInfoActivity.class);
				//intent = new Intent(context, ParkingInfoActivity.class);
				//intent.putExtra(MdMarkerItemizedOverlay.OBJECT, (Parking)markersExtra.get(itemTappedIndex));
				intent.putExtra(LoginActivity.CLIENT_OBJECT, client);
				//intent.putExtra(MdMarkerItemizedOverlay.OVERLAY_DATA, MdMapView.PARKING_OVERLAY_INDEX);
				((Activity) context).startActivityForResult(intent, MdMapActivity.PARKING_INTENT_ID);
				return true;
				
			case MdMapView.SEARCH_PARKING_OVERLAY_INDEX:
				intent.setClass(context, ParkingInfoActivity.class);
				//intent = new Intent(context, ParkingInfoActivity.class);
				//intent.putExtra(MdMarkerItemizedOverlay.OBJECT, (Parking)markersExtra.get(itemTappedIndex));
				intent.putExtra(LoginActivity.CLIENT_OBJECT, client);
				//intent.putExtra(MdMarkerItemizedOverlay.OVERLAY_DATA, MdMapView.SEARCH_PARKING_OVERLAY_INDEX);
				((Activity) context).startActivityForResult(intent, MdMapActivity.PARKING_INTENT_ID);
				return true;
				
			case MdMapView.SEARCH_ADDRESS_OVERLAY_INDEX:
				//intent = new Intent(context, AddressInfoActivity.class);
				//intent.putExtra(MdMarkerItemizedOverlay.OBJECT, markersExtra.get(itemTappedIndex));
				intent.setClass(context, AddressInfoActivity.class);
				intent.putExtra(MdMarkerItemizedOverlay.STRING_DATA, markers.get(itemTappedIndex).getTitle());
				intent.putParcelableArrayListExtra(MdMarkerItemizedOverlay.LIST, serviceList);
				//((Activity) context).startActivityForResult(intent, MdMapActivity.DIRECTIONS_INTENT_ID);
				((Activity) context).startActivityForResult(intent, MdMapActivity.SEARCH_ADDRESS_INTENT_ID);
				return true;
				
		}
		return false;
	}

	@Override
	public boolean onDoubleTapEvent(MotionEvent arg0) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean onSingleTapConfirmed(MotionEvent arg0){
		// TODO Auto-generated method stub
		String label = markers.get(itemTappedIndex).getTitle();
		if(label!=null && label.length()>0)
			Toast.makeText(context, label, Toast.LENGTH_SHORT).show();
		return true;
	}

	public boolean contains(OverlayItem item) {
		// TODO Auto-generated method stub
		int size = this.markers.size();
		for(int i=0; i<size; i++){
			int latE6 = markers.get(i).getPoint().getLatitudeE6();
			int lonE6 = markers.get(i).getPoint().getLongitudeE6();
			String title = markers.get(i).getTitle();
			
			if(	latE6 == item.getPoint().getLatitudeE6() 	&&
				lonE6 == item.getPoint().getLongitudeE6()	&&
				title.contentEquals(item.getTitle()))
				return true;
		}
		return false;
	}
	
	public int contains(GeoPoint pos, String name) {
		// TODO Auto-generated method stub
		int size = this.markersExtra.size();
		for(int i=0; i<size; i++){
			int latE6 = ((MdService) markersExtra.get(i)).getPosition().getLatitudeE6();
			int lonE6 = ((MdService) markersExtra.get(i)).getPosition().getLongitudeE6();
			String title = ((MdService) markersExtra.get(i)).getName();
			
			if(	latE6 == pos.getLatitudeE6() 	&&
				lonE6 == pos.getLongitudeE6()	&&
				title.contentEquals(name))
				return i;
		}
		return -1;
	}
	
	public void setClient(Client c){
		this.client = c;
	}
	
	public int getOverlayId(){
		return this.overlayId;
	}
}
